package com.gxa.security.security.config;


import com.gxa.security.security.filter.TokenAuthenticationFilter;
import com.gxa.security.security.filter.TokenAuthorizationFilter;
import com.gxa.security.security.security.DefaultPasswordEncoder;
import com.gxa.security.security.security.TokenHandler;
import com.gxa.security.security.security.TokenLogoutHandler;
import com.gxa.security.security.security.UnauthorizedEntryPointHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;

import javax.annotation.Resource;

/**
 * Security核心配置类
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
/*  @EnableGlobalMethodSecurity(prePostEnabled = true)
    在接口上通过,注解适合进入方法前的权限验证:
         @PreAuthorize("hasRole('ROLE_ 管理员 ')")
         @PreAuthorize("hasAnyAuthority('菜单管理')")
 */
//@EnableGlobalMethodSecurity(securedEnabled = true)
//在接口上通过角色控制，注意要加ROLE前缀：@Secured({"ROLE_normal","ROLE_admin"})
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private TokenHandler tokenHandler;
    @Resource
    private DefaultPasswordEncoder defaultPasswordEncoder;
    @Resource
    private UserDetailsService userDetailsService;//自定义查询数据库用户名密码和权限信息

    //配置不进行认证过滤链，直接放行，配置放行静态资源
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/js/**","/css/**");
    }

    //配置退出的地址、Token、Redis等操作
    @Override
    protected void configure(HttpSecurity http) throws Exception {
            //自定义登录路径
            http
                .exceptionHandling()
                .authenticationEntryPoint(new UnauthorizedEntryPointHandler())//没有权限访问
                .and().csrf().disable()
                 //放行登录接口
                .authorizeRequests()
                    .antMatchers("/sys/login").permitAll()
                .anyRequest().authenticated()
                .and().logout().logoutUrl("/logout")//指定退出跳转路径
                .addLogoutHandler(new TokenLogoutHandler(tokenHandler,redisTemplate))
                 .and()
                .addFilter(new TokenAuthenticationFilter(authenticationManager(),tokenHandler,redisTemplate))
                .addFilter(new TokenAuthorizationFilter(authenticationManager(),tokenHandler,redisTemplate)).httpBasic();
    }

    //调用userDetailsService和密码处理
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(defaultPasswordEncoder);
    }
}
